/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef TAIHE_AUDIO_RENDERER_DEVICE_CHANGE_CALLBACK_H
#define TAIHE_AUDIO_RENDERER_DEVICE_CHANGE_CALLBACK_H

#include <list>
#include "audio_renderer.h"
#include "event_handler.h"
#include "taihe_work.h"
#include "taihe_audio_renderer_callback.h"

namespace ANI::Audio {
using namespace taihe;
using namespace ohos::multimedia::audio;
class TaiheAudioRendererDeviceChangeCallback : public OHOS::AudioStandard::AudioRendererOutputDeviceChangeCallback,
    public std::enable_shared_from_this<TaiheAudioRendererDeviceChangeCallback> {
public:
    explicit TaiheAudioRendererDeviceChangeCallback();
    ~TaiheAudioRendererDeviceChangeCallback();
    void OnOutputDeviceChange(const OHOS::AudioStandard::AudioDeviceDescriptor &deviceInfo,
        const OHOS::AudioStandard::AudioStreamDeviceChangeReason reason) override;
    void RemoveAllCallbacks();
    int32_t GetCallbackListSize() const;
    void AddCallbackReference(std::shared_ptr<uintptr_t> callback);
    void RemoveCallbackReference(std::shared_ptr<uintptr_t> callback = nullptr);

private:
    struct AudioRendererDeviceChangeJsCallback {
        std::shared_ptr<AutoRef> callback = nullptr;
        std::string callbackName = "unknown";
        array<AudioDeviceDescriptor> deviceInfo_ = array<AudioDeviceDescriptor>(nullptr, 0);
    };
    void OnJsCallbackRendererDeviceInfo(std::unique_ptr<AudioRendererDeviceChangeJsCallback> &jsCb);
    static void SafeJsCallbackRendererDeviceInfoWork(AudioRendererDeviceChangeJsCallback *event);
    std::mutex mutex_;
    std::list<std::shared_ptr<AutoRef>> callbacks_ {};
    std::shared_ptr<AutoRef> renderPeriodPositionCallback_ = nullptr;
    std::shared_ptr<OHOS::AppExecFwk::EventHandler> mainHandler_ = nullptr;
};

class TaiheAudioRendererOutputDeviceChangeWithInfoCallback :
    public OHOS::AudioStandard::AudioRendererOutputDeviceChangeCallback,
    public std::enable_shared_from_this<TaiheAudioRendererOutputDeviceChangeWithInfoCallback> {
public:
    explicit TaiheAudioRendererOutputDeviceChangeWithInfoCallback();
    ~TaiheAudioRendererOutputDeviceChangeWithInfoCallback();
    void OnOutputDeviceChange(const OHOS::AudioStandard::AudioDeviceDescriptor &deviceInfo,
        const OHOS::AudioStandard::AudioStreamDeviceChangeReason reason) override;
    int32_t GetCallbackListSize() const;
    void AddCallbackReference(std::shared_ptr<uintptr_t> callback);
    void RemoveCallbackReference(std::shared_ptr<uintptr_t> callback = nullptr);

private:
    struct AudioRendererOutputDeviceChangeWithInfoJsCallback {
        std::shared_ptr<AutoRef> callback = nullptr;
        std::string callbackName = "unknown";
        array<AudioDeviceDescriptor> deviceInfo_ = array<AudioDeviceDescriptor>(nullptr, 0);
        OHOS::AudioStandard::AudioStreamDeviceChangeReason reason_;
    };

    void OnJsCallbackOutputDeviceInfo(std::unique_ptr<AudioRendererOutputDeviceChangeWithInfoJsCallback> &jsCb);
    static void SafeJsCallbackOutputDeviceInfoWork(AudioRendererOutputDeviceChangeWithInfoJsCallback *event);

    std::mutex mutex_;
    std::list<std::shared_ptr<AutoRef>> callbacks_ {};
    std::shared_ptr<OHOS::AppExecFwk::EventHandler> mainHandler_ = nullptr;
};
} // namespace ANI::Audio
#endif // TAIHE_AUDIO_RENDERER_DEVICE_CHANGE_CALLBACK_H
